home *** CD-ROM | disk | FTP | other *** search
/ Network Support Library / RoseWare - Network Support Library.iso / apidev / envp.arc / ENVP.C next >
Text File  |  1989-01-15  |  10KB  |  368 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <dos.h>
  4. #include <fcntl.h>
  5. #include <types.h>
  6. #include <stat.h>
  7. #include <string.h>
  8. #include <dos.h>
  9. #include <direct.h>
  10.  
  11. /* $$cc: -w3 -nh   */
  12.  
  13. /*
  14.     (c) Cyco software, the Netherlands, januari 1989
  15.  
  16.     Routines to handle the environment of the parent proces.
  17.     A normal DOS process only gets a copy of the original environment.
  18.     Any changes made to that environment are only accessable to child
  19.     programs (programs that the parent program runs).
  20.     These routines may be used to change the environment of the parent.
  21.     In most cases the parent process is COMMAND.COM, so with these
  22.     routines you can build your own dos 'SET' statement.
  23.     The example included at the bottom sets the current drive and
  24.     directory in the environment variables DRV and CWD. In batch
  25.     files they can be used with the %DRV% and %CWD% method.
  26.  
  27.     This code should be compiled with Microsoft C5 compiler. Any
  28.     memory model should work properly.
  29.  
  30.     This program code may be copied and changed for own use as long
  31.     as the copyright line in top is maintained. Any comments please
  32.     reply them to me:
  33.  
  34.     Bart Mellink
  35.     Cyco Automation
  36.     Adm. Banckertweg 2a
  37.     2315 SR  Leiden
  38.     The Netherlands
  39.     phone: (int)-31-71-222707
  40.     fax:   (int)-31-71-224979
  41.     compuserve easyplex 76702,256
  42.  
  43. */
  44.  
  45. #define    OK    0
  46. #define    ERROR    -1
  47. #define    TRUE    1
  48. #define    FALSE    0
  49.  
  50.  
  51. /*------------------------- code ------------------------*/
  52.  
  53. unsigned ParentEnvseg(void) {
  54.     char far *p;
  55.     unsigned parseg;
  56.     static unsigned parentenv = 0;
  57.  
  58.     /* Get segment address of Parents Environment.
  59.        In our own PSP there is a undocumented pointer to the PSP
  60.        of the parent proces at offset 16-hex. 
  61.        In most processes we can find a pointer to the environment
  62.        at offset 2C in the PSP. For command.com itself (that is
  63.        mostly our parent) this holds only for DOS 3.30, so we 
  64.        have to find another way.
  65.        
  66.     */
  67.     
  68.     if (parentenv != 0)    /* we allready did this routine before */
  69.         return parentenv;
  70.  
  71.     FP_SEG(p) = _psp;
  72.     FP_OFF(p) = 0;    
  73.     parseg = *(unsigned far *)(p+0x016);
  74.  
  75.     /* Try an alternative way to get the segment of the parent's
  76.        environment. We allready have the segment of the parent program
  77.        in parseg. Mostly one segment (16 bytes) before that segment
  78.        is the DOS malloc infoblock of that segment. By following the
  79.        DOS malloc chain we can find the environment.
  80.        The DOS malloc info block consists of:
  81.          4D    -- code (last one is 5a)
  82.          WORD  -- segment of owner (should be running command.com)
  83.                   but can be zero in case of an orphan block
  84.          WORD  -- number of segments of that block
  85.     */
  86.  
  87.     FP_SEG(p) = parseg - 1;    /* previous segment */
  88.     FP_OFF(p) = 0;
  89.  
  90.     if ((*p != 0x4d) || (parseg != * (unsigned far *)(p+1)))
  91.         return 0;            /* can't find it */
  92.  
  93.     FP_SEG(p) += * (unsigned far *)(p+3) + 1; /* next block    */
  94.  
  95.     while ((*p == 0x4d)  &&  (parseg != * (unsigned far *)(p+1))) {
  96.         FP_SEG(p) += * (unsigned far *)(p+3) + 1; /* next block    */
  97.     }
  98.  
  99.     if (*p != 0x4d)
  100.         return 0;
  101.  
  102.     parentenv = (FP_SEG(p) + 1);
  103.  
  104.     return parentenv;
  105. }
  106.  
  107. char far * ParentEnv(void) {
  108.     char far *p;
  109.  
  110.     /* Returns far pointer to the parents environment */
  111.  
  112.     FP_SEG(p) = ParentEnvseg();
  113.     FP_OFF(p) = 0;
  114.     return p;
  115. }
  116.  
  117.  
  118. unsigned ParentEnvMaxSize(void) {
  119.     union REGS inregs, outregs;
  120.     struct SREGS segregs;
  121.  
  122.     /* The environment is a DOS allocatable block, so we use
  123.        the dos setblock function to set the size to maximum.
  124.        (dos return number of segments).
  125.        Then we have the environment size we can max use.
  126.        Works only for small blocks (<64k), but the environment
  127.        is mostly smaller, so that's no point.
  128.        This routine returns number of bytes that can be max in environ-
  129.        ment.
  130.     */
  131.  
  132.     inregs.h.ah = 0x04a;        /* function */
  133.     inregs.x.bx = 0x08000;        /* try large space */
  134.     segregs.es = ParentEnvseg();     /* segment address */
  135.  
  136.     if (segregs.es == 0)        /* illegal */
  137.         return 0;
  138.  
  139.     int86x(0x021, &inregs, &outregs, &segregs);
  140.     return (outregs.x.bx * 16);
  141. }
  142.  
  143. unsigned ParentEnvSize(void) {
  144.     char far *p;
  145.     unsigned i=2; /* at least 2 nulls */
  146.  
  147.     /* Calculate the space of the parents environment. The
  148.        environment consists of multiple strings that are null
  149.        terminated. A double null is the end of the environment.
  150.     */
  151.  
  152.     p = ParentEnv();
  153.  
  154.     if (p==NULL)
  155.         return 0;
  156.  
  157.     while ((*p!='\0') || (*(p+1)!='\0')) {
  158.         i++; p++;
  159.     }
  160.     return i;
  161. }
  162.  
  163. unsigned ParentEnvFree(void) {
  164.     /* returns free space in environment */
  165.     return ParentEnvMaxSize() - ParentEnvSize();
  166. }
  167.  
  168. static int farstrncmp(char * nearstr, char far * farstr) {
  169.  
  170.     /* string compare working on one far pointer
  171.        Returns TRUE or FALSE. 
  172.        Returns TRUE if all characters in the nearstring are
  173.        the same as the first ones in the farstring.
  174.     */
  175.  
  176.     while (*nearstr && *farstr) {
  177.         if (*nearstr++ != *farstr++) return FALSE;
  178.     }
  179.     if (*nearstr)
  180.         return FALSE;        /* farstring too short */
  181.     else
  182.         return TRUE;    
  183. }
  184.  
  185. static unsigned farstrlen(char far * str) {
  186.     unsigned i = 0;
  187.     while (*str++) i++;
  188.     return i;
  189. }
  190.  
  191. static int cinstr(char *p, char c) {
  192.     int i=0;
  193.     /* look if character c is inside string p */
  194.     while (*p) {
  195.         if (*p == c) return i;
  196.         p++; i++;
  197.     }
  198.     return ERROR;
  199. }
  200.  
  201. /* --------------- the most important routines -------------------- */
  202.  
  203. char far * ParentGetenv(char * varname) {
  204.     char far *p;
  205.  
  206.     /* Look if the variable varname is in the environment
  207.        of the parent process. 
  208.        If yes return pointer to the string (far pointer!). 
  209.        If not return NULL.
  210.        
  211.        This routine is a little different from the microsoft lib
  212.        version: it returns a far pointer, because the environment
  213.        can be anywhere in memory.
  214.     */
  215.     
  216.     p = ParentEnv();
  217.     if (p==NULL)
  218.         return NULL;
  219.  
  220.     while ((*p!='\0') || (*(p+1)!='\0')) {
  221.         if (*p == '\0') 
  222.             p++;
  223.         if (farstrncmp(varname, p) && (*(p+strlen(varname))=='=')) {
  224.                 return (p+strlen(varname)+1);
  225.         }
  226.         while (*p) 
  227.             p++;
  228.     }
  229.     return NULL;
  230. }
  231.  
  232. int ParentPutenv(char * envstr) {
  233.  
  234.     /* Put the string envstr in the environment of the parent
  235.        process. The envstr normally has a NAME=STRING syntax.
  236.        In that case it replaces the old NAME= value in the
  237.        environment.
  238.        If however the NAME= syntax is not used, the bare string
  239.        is placed in the environment. This has normally no use, but
  240.        for the sake of compatibility with the microsoftlib version
  241.        of 'putenv'.
  242.  
  243.        Returns:
  244.        If the environment is full ERROR is returned otherwise OK.
  245.  
  246.        Side effect:
  247.        The NAME= part is converted to upper case (as it should be)
  248.     */    
  249.     char *q, *substr;
  250.     char far *p = ParentEnv();
  251.     char far *p2;
  252.     unsigned envstrlen = strlen(envstr);
  253.  
  254.     if (p==NULL)
  255.         return ERROR;
  256.     
  257.     if (cinstr(envstr, '=') != ERROR) {
  258.         /* we have a '=' sign there */
  259.         q = envstr;
  260.         while (*q != '=') {
  261.             *q = (char) toupper(*q);
  262.             q++;
  263.         }
  264.         *q = '\0';    /* split temporary for getenv() function */
  265.         substr = q+1;     /* pointer behind "=" in envstr */
  266.         if ((p = ParentGetenv(envstr)) != NULL) {
  267.             /* we know the string is allready there, calc size */
  268.             if (strlen(substr)+1 > farstrlen(p)+ParentEnvFree()) {
  269.                 *q = '=';        /* restore old envstr */        
  270.                 return ERROR;         /* no room */
  271.             }
  272.  
  273.             /* now delete old string */
  274.  
  275.             p -= (strlen(envstr)+1); /* begin of old parent string */
  276.             p2 = p + farstrlen(p);   /* end of string (null char) */
  277.             
  278.             while ((*p2!='\0') || (*(p2+1)!='\0')) {
  279.                 *p++ = *(p2+1);
  280.                 p2++;
  281.             }
  282.             *p = '\0';
  283.         
  284.             /* test if substring is empty (remove from env) */
  285.             if (strlen(substr)==0) {
  286.                 *q = '=';    /* restore old envstr */        
  287.                 return OK;
  288.             }    
  289.  
  290.         }
  291.         *q = '=';    /* restore old envstr */        
  292.     }
  293.     /* look if we have enough room */
  294.     if (strlen(envstr)+1 > ParentEnvFree())
  295.         return ERROR;
  296.  
  297.     /* set pointer at end of parent environment and copy string */
  298.     p = ParentEnv() + ParentEnvSize() - 1;
  299.     while (*envstr) {
  300.         *p++ = *envstr++;
  301.     }
  302.     *p ++ = '\0';    /* add a double null */
  303.     *p ++ = '\0';
  304.     return OK;
  305. }
  306.  
  307. /* ---------------------- test program ----------------------- */
  308.  
  309. void main(int argc, char **argv) {
  310.     char far *p;
  311.     unsigned envmaxsize;
  312.     int i;
  313.     char buf1[80], buf2[80];
  314.     
  315.     printf("(c) `88 Cyco Software, the Netherlands.\n");
  316.     
  317.     p = ParentEnv();
  318.     envmaxsize = ParentEnvMaxSize();
  319.  
  320.     printf("PSP (our)     = %x (hex)\n", _psp);
  321.     printf("ENV of parent = %x (hex)\n", ParentEnvseg());
  322.     printf("ENV max size  = %d bytes\n", envmaxsize);
  323.     printf("ENV size      = %d bytes\n", ParentEnvSize());
  324.     printf("ENV free      = %d bytes\n", ParentEnvFree());
  325.  
  326.     printf("\n");
  327.  
  328.     /* print here the environment */
  329.     for (i=0; i<envmaxsize; i++) {
  330.         if (*p == 0) {
  331.             p++; printf("\n");
  332.             if (*p == 0) {
  333.                 break;
  334.             }
  335.         }
  336.         else {
  337.             putchar(*p++);
  338.         }
  339.     }
  340.     
  341.     /* put the current drive in DRV and directory in CWD */
  342.     if (getcwd(buf1, 79) != NULL) {
  343.         sprintf(buf2, "CWD=%s", buf1+2);
  344.         printf("\nErrorcode putenv --%s-- is %d", buf2, ParentPutenv(buf2));
  345.         sprintf(buf2, "DRV=%c:", *buf1);
  346.         printf("\nErrorcode putenv --%s-- is %d", buf2, ParentPutenv(buf2));
  347.     }
  348.  
  349.     if (argc==1) {
  350.         printf("\nFirst argument is passed to getenv, second to putenv.");
  351.     }
  352.  
  353.     if (argc>1) {
  354.         p = ParentGetenv(argv[1]);
  355.         if (p==NULL)
  356.             printf("Can't find --%s-- in environment\n", argv[1]);
  357.         else {
  358.             printf("String of environment variable %s = ", argv[1]);
  359.             while (*p)
  360.                 putchar(*p++);
  361.         }
  362.         printf("\n\n");
  363.     }
  364.     if (argc>2) {
  365.         printf("Putenv --%s-- returns code %d\n", argv[2], ParentPutenv(argv[2]));
  366.     }
  367. }
  368.